grammar YAGI;

options {
  language = Java;
  output = AST;
  ASTLabelType = CommonTree;
  backtrack = true;
}

@header {
//  package com.yagi;
}

// main

line	:	declaration 
	| 	block
	;


declaration
	:	fluent_decl ';'
	|	fact_decl ';'
	|	action_decl
	| 	proc_decl
	|	assignment
	;
	

// proc declaration

proc_decl
	:	'proc' ID '(' varlist ')' block 'end proc'
	;

// extended statemens (golog)

block
	:	(statement)*
	;

statement
	:	action_exec ';'
	|	pick
	|	test ';'
	|	for_loop
	|	if_then_else
	|	choose
	;

action_exec
	:	ID '(' arglist')'
	;
	
arglist
	:	
	|	value ( ',' value )*
	;

pick	:	'pick' var 'from' setexpr 'such' block 'end pick'
	;

test	:	'test' formula
	;
	
for_loop:	'for' var 'in' setexpr 'do' block 'end for'
	;	

if_then_else
	:	'if' formula 'then' block ('else' block)? 'end if'
	;

choose	:	'choose' block ( 'or' block )+ 'end choose'
	;


	
// action declaration

action_decl
	:	'action' ID '(' varlist ')'
		('precondition:' formula)?
		('effect:' assignment)?
		('signal:' valexpr)?
		'end action'
	;

varlist
	:	
	|	var ( ',' var )*
	;


// statements


assignment
	:	assign ';'
	|	for_loop_assign
	|	conditional_assign
	;

for_loop_assign
	:	'for' var 'in' setexpr 'do' assignment 'end for'
	;
	
conditional_assign
	:	'if' formula 'then' assignment ('else' assignment)? 'end if'
	;

assign	
	:	term assign_op setexpr
	|	var assign_op valexpr
	;
	
assign_op
	:	'='
	| 	'+='
	| 	'-='
	;

// formulas

formula	:	atom
	|	'not' '(' formula ')'
	|	'(' atom connective formula ')'
	|	'exists' var 'in' setexpr 'such' formula
	|	'all' var 'in' setexpr 'such' formula
	;
	
connective
	:	'and'
	|	'or'
	;	

atom
	:	valexpr comp_op valexpr
	|	setexpr comp_op setexpr
	|	value 'in' setexpr
	|	('true' | 'false')
	;
	
comp_op
	:	'=='
	|	'!='
	|	'<='
	|	'>='	
	|	'<'
	|	'>'
	;

	
//  expressions


setexpr	:	set (('+'|'-') set)*
	;

set
	:	'{' value ( ',' value )* '}'
	|	term
	;

term
 	:	ID ( '[' value ']' )*
	;

valexpr	:	value (('+'|'-') value)*
	;

value
	:	INT
	|	STRING
	|	var
	;

var
	:	'$' ID
	;

	
// fluent/fact and var declaration

fluent_decl
	:	'fluent' ID ('[' ']')* 
	;

fact_decl
	:	'fact' ID ('[' ']')* 
	;

var_decl
	:	'local' '$' ID 
	;


// lexicon

WHITESPACE : ( '\t' | ' ' | '\r' | '\n'| '\u000C' )+    { $channel = HIDDEN; } ;

ID  :	('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
    ;

INT :	'0'..'9'+
    ;

STRING
    :  '"' ( ~('\\'|'"') )* '"'
    ;

COMMENT
    :   '//' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;}
    |   '/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;}
    ;